#include "board.h"

#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"

#include "bl_fw_api.h"
#include "bflb_irq.h"
#include "bl616_glb.h"
#include "rfparam_adapter.h"
#include "wifi_mgmr_ext.h"
#include "wifi_mgmr.h"
#include <lwip/api.h>
#include <lwip/arch.h>
#include <lwip/opt.h>
#include <lwip/inet.h>
#include <lwip/errno.h>
#include <lwip/tcpip.h>
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#include <netdb.h>
#include <unistd.h>

#include "bflb_uart.h"
#include "bflb_dma.h"
#include "bflb_gpio.h"
#include "bflb_pwm_v2.h"
#include "bflb_clock.h"
#include "bflb_adc.h"

#include "MPU6050.h"
#include "OLED.h"
#include "DY_SV17F.h"
/* 各线程栈大小 */
#define WIFI_FW_STACK_SIZE           (1536)             // wifi firmware初始化
#define WIFI_STACK_SIZE              (2028)             // 循环发送至onenet平台 注意大小，太小发不出去
#define COMMAND_STACK_SIZE           (1024)
#define REMIND_STACK_SIZE            (128)

/* 各线程优先级 */
#define TASK_PRIORITY_WIFI_FW        (13)       
#define TASK_PRIORITY_WIFI           (14)
#define TASK_PRIORITY_COMMAND        (12)
#define TASK_PRIORITY_REMIND         (15)

/* 各线程 */
TaskHandle_t WIFI_FW_handle;
TaskHandle_t WIFI_handle;
TaskHandle_t COMMAND_handle;
TaskHandle_t REMIND_handle;

/* Wi-Fi */
wifi_conf_t conf = {.country_code = "CN"};
char SSID[16] = "";
char KEY[16] =  "";

/* onenet */
#define HOST_NAME "183.230.40.33"
#define ONENET_HTTP_POST_MAX_LEN 2028
#define ONENET_HTTP_POST_CONTENT_MAX_LEN 2028
#define DEV_ID  "1108138101"                     //设备ID
#define API_KEY "z2sZONGV9WeCnWNH3oIzjnvF08Q="   //API-KEY
int sock_client = -1;                            // socket连接状态
uint32_t recv_buf[4 * 1024] = {0};               // 访问返回信息
uint64_t total_cnt = 0;                          // 总字节

/* ble command */
#define BLE_UART           "uart1"
#define BLE_DMA_TX         "dma0_ch0"
#define BLE_DMA_RX         "dma0_ch1"
#define BLE_DMA_TX_ADDR     DMA_ADDR_UART1_TDR
#define BLE_DMA_TX_SRC_REQ  DMA_REQUEST_UART1_TX
#define BLE_DMA_RX_ADDR     DMA_ADDR_UART1_RDR
#define BLE_DMA_RX_SRC_REQ  DMA_REQUEST_UART1_RX
static struct bflb_device_s *ble_uart;
static struct bflb_device_s *ble_dma_rx;
static ATTR_NOCACHE_NOINIT_RAM_SECTION uint8_t ble_command_rx[1];
struct bflb_dma_channel_lli_pool_s ble_llipool_rx[1];
struct bflb_dma_channel_lli_transfer_s ble_transfers_rx[1];
static struct bflb_device_s *ble_dma_tx;
static ATTR_NOCACHE_NOINIT_RAM_SECTION uint8_t ble_command_tx[1];
struct bflb_dma_channel_lli_pool_s ble_llipool_tx[1];
struct bflb_dma_channel_lli_transfer_s ble_transfers_tx[1];
/* remind */
static struct bflb_device_s *pwm;
uint8_t remind_flag = 0;
uint8_t remind_status = 0;
uint8_t remind_rank = 25;
/* adc */
struct bflb_device_s *adc;
/* function */
void ble_command_Init(void);
void wifi_event_handler(uint32_t code);
uint8_t wifi_start_firmware_Init(void);
void adc_Init(void);
void adc_get(void);
void VIBRATION_Init(void);
void COMMAND_task(void *pvParameters);
void REMIND_task(void *pvParameters);
void WIFI_task(int argc, char **argv);

int main(void)
{
    board_init();

    OLED_Init();
    MPU6050_Init();
    adc_Init();
    VIBRATION_Init();
    DYSV17F_Uart_Init();
    ble_command_Init();
    xTaskCreate(COMMAND_task, 
                (char *)"COMMAND_task", 
                COMMAND_STACK_SIZE, 
                NULL, 
                TASK_PRIORITY_COMMAND, 
                &COMMAND_handle);
    
    vTaskStartScheduler();
    while(1)
    {
        //
    }
    return 0;
}

void WIFI_task(int argc, char **argv)
{
    /* Http client task start */
    char *host_name;
    char *addr;
    char *port;
    struct sockaddr_in remote_addr;
    if (argc > 1) {
    /* get address (argv[1] if present) */
    host_name = argv[1];
#ifdef LWIP_DNS
    ip4_addr_t dns_ip;
    netconn_gethostbyname(host_name, &dns_ip);
    addr = ip_ntoa(&dns_ip);
#endif
    }
    else {
        addr = HOST_NAME;
    }
    /* get port number (argv[2] if present) */
    if (argc > 2) {
        port = argv[2];
    } else {
        port = "80";
    }

    while (1)
    {
        if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            // Http Client create socket error
            return;
        }
        /* 准备数据 */
        MPU6050_GetData();

        remote_addr.sin_family = AF_INET;
        remote_addr.sin_port = htons(atoi(port));
        remote_addr.sin_addr.s_addr = inet_addr(addr);
        memset(&(remote_addr.sin_zero), 0, sizeof(remote_addr.sin_zero));
        //printf("Host:%s, Server ip Address : %s:%s\r\n", HOST_NAME, addr, port);
        if (connect(sock_client, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) != 0) {
            // Http client connect server falied!
            closesocket(sock_client);
            return;
        }
        // Http client connect server success!
        memset(recv_buf, 0, sizeof(recv_buf));
        total_cnt = 0;
        /* 创建post数据 */
        char post_buf[ONENET_HTTP_POST_MAX_LEN];
        char post_content[ONENET_HTTP_POST_CONTENT_MAX_LEN];
        char post_content_len[4];
        memset(post_content, 0, sizeof(post_content));
        memset(post_buf, 0, sizeof(post_buf));
        sprintf(post_content,"{\"datastreams\":["
                                                "{\"id\":\"roll\",\"datapoints\":[{\"value\":%.2f}]},"
                                                "{\"id\":\"accel_x\",\"datapoints\":[{\"value\":%.2f}]},"
                                                "{\"id\":\"accel_y\",\"datapoints\":[{\"value\":%.2f}]},"
                                                "{\"id\":\"accel_z\",\"datapoints\":[{\"value\":%.2f}]},"
                                                "]}",roll_kalman,ax_f,ay_f,az_f);// 发送数据
        sprintf(post_content_len,"%d",strlen(post_content));
        strcat(post_buf, "POST /devices/");
        strcat(post_buf, DEV_ID);
        strcat(post_buf, "/datapoints HTTP/1.1\r\n");
        strcat(post_buf, "api-key:");
        strcat(post_buf, API_KEY);
        strcat(post_buf, "\r\n");
        strcat(post_buf, "Host:api.heclouds.com\r\n");
        strcat(post_buf, "Content-Length:");
        strcat(post_buf, post_content_len);
        strcat(post_buf, "\r\n\r\n");
        strcat(post_buf, post_content);
        strcat(post_buf, "\r\n\r\n");
        write(sock_client, post_buf, sizeof(post_buf));
        while (1)
        {
            total_cnt = recv(sock_client, (uint8_t *)recv_buf, sizeof(recv_buf), 0);
            if (total_cnt <= 0) // 接收失败
                break;
            vTaskDelay(500);
        }
        closesocket(sock_client);
    }
}

void REMIND_task(void *pvParameters)
{
    uint32_t i;
    switch (remind_flag)
    {
        case 1: // 37
            remind_status = 0;
            break;
        case 2: // 38
            remind_status = 1;
            break;
        case 3: // 停止播放 39
            DYSV17F_ControlCommand(ControlCommand_Stop);
            break;
        default:
            if(remind_status == 1) // 语音模式
            {
                switch (remind_flag)
                {
                    case 4: // 40
                        if(remind_status == 1)
                        DYSV17F_Set_AppointPath(Drive_FLASH,"/001*MP3");// 眼保健操
                        break;
                    case 5: // 41
                        DYSV17F_Set_AppointPath(Drive_FLASH,"/002*MP3");// 请注意体态
                        break;
                    case 6: // 42
                        DYSV17F_Set_AppointPath(Drive_FLASH,"/004*MP3");// 该喝水啦
                        break;
                    case 7: // 43
                        DYSV17F_Set_AppointPath(Drive_FLASH,"/003*MP3");// 该休息啦
                        vTaskDelay(1300);
                        DYSV17F_Set_AppointPath(Drive_FLASH,"/005*MP3");// 您已久坐十分钟
                        break;
                    case 8: // 44
                        DYSV17F_Set_AppointPath(Drive_FLASH,"/003*MP3");// 该休息啦
                        vTaskDelay(1300);
                        DYSV17F_Set_AppointPath(Drive_FLASH,"/006*MP3");// 您已久坐半小时
                        break;
                    case 9: // 45
                        DYSV17F_Set_AppointPath(Drive_FLASH,"/003*MP3");// 该休息啦
                        vTaskDelay(1300);
                        DYSV17F_Set_AppointPath(Drive_FLASH,"/007*MP3");// 您已久坐一小时
                        break;
                default:
                    break;
                }
            }
            else    // 振动模式
            {
                if(remind_rank)
                {
                    bflb_pwm_v2_channel_set_threshold(pwm, PWM_CH1, (240 - (remind_rank * 8)), 999);
                    vTaskDelay(800);
                }
                bflb_pwm_v2_channel_set_threshold(pwm, PWM_CH1, 0, 0);
            }
            break;
    }
    vTaskDelete(NULL);
}

void COMMAND_task(void *pvParameters)
{
    static uint8_t i = 0;
    static uint8_t wifi_i = 0, wifi_j = 0, wifi_elc = 0;// elc为0填ssid，为1填key
    static uint8_t status_flag = 1;
    static uint8_t conn_wifi = 0;
    OLED_ShowString(2,1,"value:");
    while (1)
    {
        OLED_ShowNum(2,7,ble_command_rx[0],3);
        
        adc_get();

        if(status_flag == 1) // 命令模式
        {
            if((ble_command_rx[0] >= 1)&&(ble_command_rx[0] <= 31)) //1-31对应音量强度0~30
            {
                DYSV17F_Set_Voice(ble_command_rx[0] - 1);
            }
            if(ble_command_rx[0] == 32)// 连接ble
            {
                OLED_ShowString(3,1,"ble conn succ  ");
            }
            if(ble_command_rx[0] == 33)// 断开ble
            {
                OLED_ShowString(3,1,"ble broken     ");
            }
            if(ble_command_rx[0] == 34)
            {
                status_flag = 2;
                for(i=0; i<16; i++)
                {
                    SSID[i] = 0;
                }
                for(i=0; i<16; i++)
                {
                    KEY[i] = 0;
                }
            }
            if(ble_command_rx[0] == 35)
            {
                if(!conn_wifi)
                {
                    tcpip_init(NULL, NULL);
                    wifi_start_firmware_Init();
                    xTaskCreate(wifi_main, 
                                (char *)"wifi_fw_task", 
                                WIFI_FW_STACK_SIZE, 
                                NULL, 
                                TASK_PRIORITY_WIFI_FW, 
                                &WIFI_FW_handle);
                    conn_wifi = 1;
                }
                else
                {
                    // 返回  1成功，2为失败
                    if(wifi_sta_connect(SSID,KEY,NULL,NULL,1,0,0,1) == 0)
                    {
                        OLED_ShowString(4,1,"wifi conn ...  ");
                    }
                    else
                    {
                        ble_command_tx[0] = 3;
                        bflb_dma_channel_lli_reload(ble_dma_tx, ble_llipool_tx, 1, ble_transfers_tx, 1);
                        bflb_dma_channel_start(ble_dma_tx);
                    }
                }
            }
            if(ble_command_rx[0] == 36)// 断开wifi
            {
                wifi_sta_disconnect();
            }
            if((ble_command_rx[0] >= 37) && (ble_command_rx[0] <= 49))// 提醒
            {
                remind_flag = ble_command_rx[0] - 36;
                xTaskCreate(REMIND_task, 
                            (char *)"REMIND_task", 
                            REMIND_STACK_SIZE, 
                            NULL, 
                            TASK_PRIORITY_REMIND, 
                            &REMIND_handle);
            }
            if((ble_command_rx[0] >= 50) && (ble_command_rx[0] <= 80))// 提醒
            {
                remind_rank = ble_command_rx[0] - 50;
            }
            if(ble_command_rx[0] != 0)
            {
                ble_command_rx[0] = 0;
                bflb_dma_channel_lli_reload(ble_dma_rx, ble_llipool_rx, 1, ble_transfers_rx, 1);
                bflb_dma_channel_start(ble_dma_rx);
            }
        }
        if(status_flag == 2) // 输入wifi信息
        {
            if((ble_command_rx[0] != 0xff)&&(ble_command_rx[0] != 0))
            {
                if(wifi_elc == 0)
                {
                    SSID[wifi_i] = ble_command_rx[0];
                    wifi_i++;
                }
                if(wifi_elc == 1)
                {
                    KEY[wifi_j] =  ble_command_rx[0];
                    wifi_j++;
                }
            }
            if(ble_command_rx[0] == 0xff)
            {
                if(wifi_elc == 1)
                {
                    status_flag = 1;
                    wifi_j = 0;
                    wifi_elc = 0;
                }
                if(wifi_elc == 0)
                {
                    wifi_i = 0;
                    wifi_elc = 1;
                }
            }
            bflb_dma_channel_lli_reload(ble_dma_rx, ble_llipool_rx, 1, ble_transfers_rx, 1);
            bflb_dma_channel_start(ble_dma_rx);

        }
        
        vTaskDelay(500);
    }
    
}

void VIBRATION_Init(void)
{   
    struct bflb_device_s *gpio;
    gpio = bflb_device_get_by_name("gpio");
    pwm = bflb_device_get_by_name("pwm_v2_0");
    bflb_gpio_init(gpio, GPIO_PIN_25, GPIO_FUNC_PWM0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);
    struct bflb_pwm_v2_config_s cfg = {
        .clk_source = BFLB_SYSTEM_XCLK,
        .clk_div = 40,
        .period = 1000,
    };
    bflb_pwm_v2_init(pwm, &cfg);
    bflb_pwm_v2_channel_set_threshold(pwm, PWM_CH1, 999, 999);
    bflb_pwm_v2_channel_positive_start(pwm, PWM_CH1);
    bflb_pwm_v2_start(pwm);
}

void adc_get(void)
{
    uint32_t raw_adc;
    struct bflb_adc_result_s result;
    bflb_adc_start_conversion(adc);
    vTaskDelay(1);
    raw_adc = bflb_adc_read_raw(adc);
    bflb_adc_parse_result(adc, &raw_adc, &result, 1);
    OLED_ShowNum(1,6,(uint32_t)(result.millivolt * 2),4);
    bflb_adc_stop_conversion(adc);
}

void adc_Init(void)
{
    struct bflb_adc_config_s cfg;
    struct bflb_adc_channel_s chan[] = {
        { .pos_chan = ADC_CHANNEL_VABT_HALF,
          .neg_chan = ADC_CHANNEL_GND}
    };
    adc = bflb_device_get_by_name("adc");
    cfg.clk_div = ADC_CLK_DIV_32;
    cfg.scan_conv_mode = false;
    cfg.continuous_conv_mode = false;
    cfg.differential_mode = false;
    cfg.resolution = ADC_RESOLUTION_16B;
    cfg.vref = ADC_VREF_3P2V;
    bflb_adc_init(adc, &cfg);
    bflb_adc_channel_config(adc, chan, 1);
    bflb_adc_vbat_enable(adc);
    OLED_ShowString(1,1,"volt:    mV");
}

uint8_t wifi_start_firmware_Init(void)
{
    /* enable wifi clock */
    GLB_PER_Clock_UnGate(GLB_AHB_CLOCK_IP_WIFI_PHY | GLB_AHB_CLOCK_IP_WIFI_MAC_PHY | GLB_AHB_CLOCK_IP_WIFI_PLATFORM);
    GLB_AHB_MCU_Software_Reset(GLB_AHB_MCU_SW_WIFI);
    /* set ble controller EM Size */
    GLB_Set_EM_Sel(GLB_WRAM160KB_EM0KB);
    if (0 != rfparam_init(0, NULL, 0)) {
        // PHY RF init failed!
        return 0;
    }
    // PHY RF init success!
    /* Enable wifi irq */
    extern void interrupt0_handler(void);
    bflb_irq_attach(WIFI_IRQn, (irq_callback)interrupt0_handler, NULL);
    bflb_irq_enable(WIFI_IRQn);
    
    return 0;
}

void wifi_event_handler(uint32_t code)
{
    switch (code)
    {
        case CODE_WIFI_ON_INIT_DONE:    // Wi-Fi Manager初始化
            wifi_mgmr_init(&conf); 
            break;
        case CODE_WIFI_ON_MGMR_DONE:    // 初始化成功后
            if(wifi_sta_connect(SSID,KEY,NULL,NULL,1,0,0,1) == 0)   //连接wifi
            {
                ble_command_tx[0] = 1;
                bflb_dma_channel_lli_reload(ble_dma_tx, ble_llipool_tx, 1, ble_transfers_tx, 1);
                bflb_dma_channel_start(ble_dma_tx);
                OLED_ShowString(4,1,"wifi conn ...  ");
            }
            else
            {
                ble_command_tx[0] = 3;
                bflb_dma_channel_lli_reload(ble_dma_tx, ble_llipool_tx, 1, ble_transfers_tx, 1);
                bflb_dma_channel_start(ble_dma_tx);
                OLED_ShowString(4,1,"wifi conn fail ");
            }
            break;
        case CODE_WIFI_ON_SCAN_DONE:
            wifi_mgmr_sta_scanlist();
            break;
        case CODE_WIFI_ON_CONNECTED:    // 连接wifi成功后
            {
                void mm_sec_keydump();
                mm_sec_keydump();
            }
            ble_command_tx[0] = 2;
            bflb_dma_channel_lli_reload(ble_dma_tx, ble_llipool_tx, 1, ble_transfers_tx, 1);
            bflb_dma_channel_start(ble_dma_tx);
            OLED_ShowString(4,1,"wifi conn succ ");
            break;
        case CODE_WIFI_ON_GOT_IP:       // 成功获取了IP地址
            xTaskCreate(WIFI_task, 
                        (char *)"WIFI_task", 
                        WIFI_STACK_SIZE, 
                        NULL, 
                        TASK_PRIORITY_WIFI, 
                        &WIFI_handle);    // 创建线程 开始发送信息至onenet平台
            break;
        case CODE_WIFI_ON_DISCONNECT:
            OLED_ShowString(4,1,"wifi broken    ");
            ble_command_tx[0] = 4;
            bflb_dma_channel_lli_reload(ble_dma_tx, ble_llipool_tx, 1, ble_transfers_tx, 1);
            bflb_dma_channel_start(ble_dma_tx);
            break;
        default:
            break;
    }
}

void ble_command_Init(void)
{
    /* gpio init */
    board_uartx_gpio_init();
    /* uart init */
    ble_uart = bflb_device_get_by_name(BLE_UART);
    struct bflb_uart_config_s cfg;
    cfg.baudrate = 2000000;
    cfg.data_bits = UART_DATA_BITS_8;
    cfg.stop_bits = UART_STOP_BITS_1;
    cfg.parity = UART_PARITY_NONE;
    cfg.flow_ctrl = 0;
    cfg.tx_fifo_threshold = 0;
    cfg.rx_fifo_threshold = 0;
    bflb_uart_init(ble_uart, &cfg);
    /* uart dma */
    bflb_uart_link_rxdma(ble_uart, true);
    ble_dma_rx = bflb_device_get_by_name(BLE_DMA_RX);
    struct bflb_dma_channel_config_s rxconfig;
    rxconfig.direction = DMA_PERIPH_TO_MEMORY;
    rxconfig.src_req = BLE_DMA_RX_SRC_REQ;
    rxconfig.dst_req = DMA_REQUEST_NONE;
    rxconfig.src_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
    rxconfig.dst_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
    rxconfig.src_burst_count = DMA_BURST_INCR1;
    rxconfig.dst_burst_count = DMA_BURST_INCR1;
    rxconfig.src_width = DMA_DATA_WIDTH_8BIT;
    rxconfig.dst_width = DMA_DATA_WIDTH_8BIT;
    bflb_dma_channel_init(ble_dma_rx, &rxconfig);
    ble_transfers_rx[0].src_addr = (uint32_t)BLE_DMA_RX_ADDR;
    ble_transfers_rx[0].dst_addr = (uint32_t)ble_command_rx;
    ble_transfers_rx[0].nbytes = 1;
    ble_command_rx[0] = 0x00;
    bflb_dma_channel_lli_reload(ble_dma_rx, ble_llipool_rx, 1, ble_transfers_rx, 1);
    bflb_dma_channel_start(ble_dma_rx);

    bflb_uart_link_txdma(ble_uart, true);
    ble_dma_tx = bflb_device_get_by_name(BLE_DMA_TX);
    struct bflb_dma_channel_config_s txconfig;
    txconfig.direction = DMA_MEMORY_TO_PERIPH;
    txconfig.src_req = DMA_REQUEST_NONE;
    txconfig.dst_req = BLE_DMA_TX_SRC_REQ;
    txconfig.src_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
    txconfig.dst_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
    txconfig.src_burst_count = DMA_BURST_INCR1;
    txconfig.dst_burst_count = DMA_BURST_INCR1;
    txconfig.src_width = DMA_DATA_WIDTH_8BIT;
    txconfig.dst_width = DMA_DATA_WIDTH_8BIT;
    bflb_dma_channel_init(ble_dma_tx, &txconfig);
    ble_transfers_tx[0].src_addr = (uint32_t)ble_command_tx;
    ble_transfers_tx[0].dst_addr = (uint32_t)BLE_DMA_TX_ADDR;
    ble_transfers_tx[0].nbytes = 1;
    ble_command_tx[0] = 0x00;
    bflb_dma_channel_lli_reload(ble_dma_tx, ble_llipool_tx, 1, ble_transfers_tx, 1);
    bflb_dma_channel_start(ble_dma_tx);
}


